#!/usr/bin/env bash

prepare_keyrings() {
	# Create output dir
	OUTPUT_DIR="$1"
	mkdir -p "$OUTPUT_DIR"

	# Pre-populate with keyring from current system
	if [[ -e "/usr/share/keyrings/" ]]; then
		cp -r "/usr/share/keyrings/." "$OUTPUT_DIR"
	fi

	# Copy additional keyrings supplied within the git project
	local keyrings="$SCRIPT_DIR/../../../externals/keyrings"
	if [[ -e $keyrings ]]; then
		cp -r "$keyrings/debian/apt-trusted-asc/." "$OUTPUT_DIR"
		cp -r "$keyrings/radxa/keyrings/." "$OUTPUT_DIR"
		cp -r "$keyrings/ubuntu/keyrings/." "$OUTPUT_DIR"
		cp -r "$keyrings/vscodium/pub.gpg" "$OUTPUT_DIR"

		# Dearmor keyrings
		for i in "$OUTPUT_DIR"/*.asc "$OUTPUT_DIR/pub.gpg"; do
			gpg --dearmor "$i"
			rm "$i"
		done
	fi
}

generate_rootfs() {
	local RSDK_TEMP
	RSDK_TEMP="$(mktemp -d "/tmp/rsdk.${PRODUCT}_${SUITE}_${EDITION}.XXXXXXXX")"
	# Need the temp folder to be viewable for apt-key to access
	chmod 0755 "$RSDK_TEMP"
	if [[ $RSDK_OPTION_DEBUG == "true" ]]; then
		echo "rsdk temp dir: $RSDK_TEMP"
	fi

	local JSONNET_ARGS=(
		"--tla-str" "product=${RSDK_OPTION_PRODUCT_OVERRIDE:-$PRODUCT}"
		"--tla-str" "suite=$SUITE"
		"--tla-str" "edition=$EDITION"
		"--tla-str" "temp_dir=$RSDK_TEMP"
		"--tla-str" "output_dir=$OUTPUT"
		"--tla-str" "build_date=$(date --iso-8601=s)"
	)
	local BDEBSTRAP_ARGS=()

	if [[ $RSDK_OPTION_DEBUG == "true" ]]; then
		BDEBSTRAP_ARGS+=("--debug")
	fi

	if [[ -n ${RSDK_OPTION_ROOTFS} ]]; then
		JSONNET_ARGS+=("--tla-str" "rootfs=$RSDK_OPTION_ROOTFS")
	fi

	if [[ -n ${RSDK_OPTION_DISTRO_MIRROR} ]]; then
		JSONNET_ARGS+=("--tla-str" "distro_mirror=$RSDK_OPTION_DISTRO_MIRROR")
	fi

	if [[ -n ${RSDK_OPTION_RADXA_MIRROR} ]]; then
		JSONNET_ARGS+=("--tla-str" "radxa_mirror=$RSDK_OPTION_RADXA_MIRROR")
	fi

	if [[ -n ${RSDK_OPTION_REPO_SUFFIX} ]]; then
		JSONNET_ARGS+=("--tla-str" "radxa_repo_suffix=$RSDK_OPTION_REPO_SUFFIX")
	fi

	if [[ -n $RSDK_OPTION_KERNEL_OVERRIDE ]]; then
		JSONNET_ARGS+=("--tla-str" "linux_override=$RSDK_OPTION_KERNEL_OVERRIDE")
	fi

	if [[ -n $RSDK_OPTION_FIRMWARE_OVERRIDE ]]; then
		JSONNET_ARGS+=("--tla-str" "firmware_override=$RSDK_OPTION_FIRMWARE_OVERRIDE")
	fi

	if [[ -n $RSDK_OPTION_VENDOR_PACKAGES ]]; then
		JSONNET_ARGS+=("--tla-code" "vendor_packages=$RSDK_OPTION_VENDOR_PACKAGES")
	fi

	if [[ -n $RSDK_OPTION_SYSTEMD_BOOT ]]; then
		JSONNET_ARGS+=("--ext-code" "sdboot=$RSDK_OPTION_SYSTEMD_BOOT")
	fi

	# Prepare keyrings
	prepare_keyrings "$RSDK_TEMP/keyrings/"

	# Prepare local apt archive
	if [[ -d $RSDK_OPTION_LOCAL_APT_ARCHIVE ]]; then
		cp -R "$RSDK_OPTION_LOCAL_APT_ARCHIVE/." "$RSDK_TEMP/debs"
	else
		mkdir -p "$RSDK_TEMP/debs"
	fi

	# Copy additional helpers
	cp -R "$SCRIPT_DIR/../../libexec/rsdk/build/." "$RSDK_TEMP/build"

	jsonnet "${JSONNET_ARGS[@]}" "$SCRIPT_DIR/../../share/rsdk/build/rootfs.jsonnet" -o "$RSDK_TEMP/rootfs.json"
	if [[ $RSDK_OPTION_DEBUG == "true" ]]; then
		cat "$RSDK_TEMP/rootfs.json"
	fi
	# Everything in $OUTPUT will be removed, so we cannot generate build-image first
	sudo bdebstrap "${BDEBSTRAP_ARGS[@]}" -c "$RSDK_TEMP/rootfs.json" --name "$OUTPUT" --force

	sudo chown "$UID:${GID:-$UID}" "$OUTPUT"
	for i in "$OUTPUT"/*; do
		if [[ $i != "$OUTPUT/$RSDK_OPTION_ROOTFS" ]] || [[ -f "$OUTPUT/$RSDK_OPTION_ROOTFS" ]]; then
			sudo chown -R "$UID:${GID:-$UID}" "$i"
		fi
	done
	cp -R "$RSDK_TEMP/debs/." "$OUTPUT/debs"

	rm -rf "$RSDK_TEMP"
}

generate_image() {
	if [[ ! -e "$OUTPUT/build-image" ]]; then
		local JSONNET_ARGS=(
			"-S"
			"--tla-str" "product=${RSDK_OPTION_PRODUCT_OVERRIDE:-$PRODUCT}"
		)

		if [[ -n ${RSDK_OPTION_EFI} ]]; then
			JSONNET_ARGS+=("--tla-code" "efi=$RSDK_OPTION_EFI")
		fi

		if [[ -n ${RSDK_OPTION_ROOTFS} ]]; then
			JSONNET_ARGS+=("--tla-str" "rootfs=$RSDK_OPTION_ROOTFS")
		fi

		if [[ -n ${RSDK_OPTION_IMAGE_NAME} ]]; then
			JSONNET_ARGS+=("--tla-str" "output=$RSDK_OPTION_IMAGE_NAME")
		fi

		if [[ -n $RSDK_OPTION_SYSTEMD_BOOT ]]; then
			JSONNET_ARGS+=("--tla-code" "sdboot=$RSDK_OPTION_SYSTEMD_BOOT")
		fi

		if [[ -n $RSDK_OPTION_SECTOR_SIZE ]]; then
			JSONNET_ARGS+=("--tla-code" "sector_size=$RSDK_OPTION_SECTOR_SIZE")
		fi

		if [[ -n ${SUITE} ]]; then
			JSONNET_ARGS+=("--tla-str" "suite=$SUITE")
		fi

		jsonnet "${JSONNET_ARGS[@]}" "$SCRIPT_DIR/../../share/rsdk/build/image.jsonnet" -o "$OUTPUT/build-image"
		chmod +x "$OUTPUT/build-image"
	fi

	pushd "$OUTPUT"
	if [[ -f $RSDK_OPTION_ROOTFS ]]; then
		./build-image
	elif [[ -d $RSDK_OPTION_ROOTFS ]]; then
		sudo ./build-image
		sudo chown "$UID:${GID:-$UID}" "$RSDK_OPTION_IMAGE_NAME"
	else
		echo "Unrecognized rootfs type for '$RSDK_OPTION_ROOTFS'." >&2
		popd
		exit 1
	fi
	popd
}

main() {
	local SCRIPT_DIR
	SCRIPT_DIR="$(dirname "$(realpath "$0")")"
	# shellcheck source=src/lib/rsdk/utils.sh
	source "$SCRIPT_DIR/../../lib/rsdk/utils.sh"

	local TEMP
	if ! TEMP="$(getopt -o "hdTm:M:i:k:f:p:s:" -l "no-efi,help,debug,test-repo,mirror:,image-name:,no-cache,override-kernel:,override-firmware:,override-product:,no-vendor-packages,debs:,sdboot,sector-size:" -n "$0" -- "$@")"; then
		return
	fi
	eval set -- "$TEMP"

	local RSDK_OPTION_EFI="${RSDK_OPTION_EFI:-true}"
	local RSDK_OPTION_DEBUG="${RSDK_OPTION_DEBUG:-false}"
	local RSDK_OPTION_REPO_SUFFIX="${RSDK_OPTION_REPO_SUFFIX:-}"
	local RSDK_OPTION_DISTRO_MIRROR="${RSDK_OPTION_DISTRO_MIRROR:-}"
	local RSDK_OPTION_RADXA_MIRROR="${RSDK_OPTION_RADXA_MIRROR:-}"
	local RSDK_OPTION_ROOTFS="${RSDK_OPTION_ROOTFS:-rootfs.tar}"
	local RSDK_OPTION_IMAGE_NAME="${RSDK_OPTION_IMAGE_NAME:-$("$SCRIPT_DIR/../../bin/rsdk" config build.default_image_name)}"
	local RSDK_OPTION_CACHE="${RSDK_OPTION_CACHE:-true}"
	local RSDK_OPTION_KERNEL_OVERRIDE="${RSDK_OPTION_KERNEL_OVERRIDE:-}"
	local RSDK_OPTION_FIRMWARE_OVERRIDE="${RSDK_OPTION_FIRMWARE_OVERRIDE:-}"
	local RSDK_OPTION_PRODUCT_OVERRIDE="${RSDK_OPTION_PRODUCT_OVERRIDE:-}"
	local RSDK_OPTION_VENDOR_PACKAGES="${RSDK_OPTION_VENDOR_PACKAGES:-true}"
	local RSDK_OPTION_LOCAL_APT_ARCHIVE="${RSDK_OPTION_LOCAL_APT_ARCHIVE:-}"
	local RSDK_OPTION_SYSTEMD_BOOT="${RSDK_OPTION_SYSTEMD_BOOT:-false}"
	local RSDK_OPTION_SECTOR_SIZE="${RSDK_OPTION_SECTOR_SIZE:-512}"

	while true; do
		TEMP="$1"
		shift
		case "$TEMP" in
		--no-cache)
			RSDK_OPTION_CACHE="false"
			;;
		--no-efi)
			RSDK_OPTION_EFI="false"
			;;
		-d | --debug)
			RSDK_OPTION_DEBUG="true"
			RSDK_OPTION_ROOTFS="rootfs"
			;;
		-T | --test-repo)
			RSDK_OPTION_REPO_SUFFIX="-test"
			;;
		-m | --mirror)
			RSDK_OPTION_DISTRO_MIRROR="$1"
			shift
			;;
		-M)
			RSDK_OPTION_RADXA_MIRROR="$1"
			shift
			;;
		-i | --image-name)
			RSDK_OPTION_IMAGE_NAME="$1"
			shift
			;;
		-h | --help)
			TEMP="$(basename "$0")"
			rsdk help "${TEMP#rsdk-}"
			return
			;;
		-k | --override-kernel)
			RSDK_OPTION_KERNEL_OVERRIDE="$1"
			shift
			;;
		-f | --override-firmware)
			RSDK_OPTION_FIRMWARE_OVERRIDE="$1"
			shift
			;;
		-p | --override-product)
			RSDK_OPTION_PRODUCT_OVERRIDE="$1"
			shift
			;;
		--no-vendor-packages)
			RSDK_OPTION_VENDOR_PACKAGES="false"
			;;
		--debs)
			RSDK_OPTION_LOCAL_APT_ARCHIVE="$1"
			shift
			;;
		--sdboot)
			RSDK_OPTION_SYSTEMD_BOOT="true"
			;;
		-s | --sector-size)
			RSDK_OPTION_SECTOR_SIZE="$1"
			shift
			;;
		--)
			break
			;;
		*)
			error "$EXIT_UNKNOWN_OPTION" "$TEMP"
			;;
		esac
	done

	if (($# == 0)); then
		"$0" --help
		return
	fi

	local PRODUCT="${1}" SUITE EDITION
	if ! jq -er --arg product "$PRODUCT" '.[] | select(.product == $product)' "$SCRIPT_DIR/../../share/rsdk/configs/products.json" &>/dev/null; then
		echo "'$PRODUCT' is not a supported product." >&2
		return 1
	fi

	SUITE="${2:-$(jq -er --arg product "$PRODUCT" '.[] | select(.product == $product).supported_suite[0]' "$SCRIPT_DIR/../../share/rsdk/configs/products.json")}"
	EDITION="${3:-$(jq -er --arg product "$PRODUCT" '.[] | select(.product == $product).supported_edition[0]' "$SCRIPT_DIR/../../share/rsdk/configs/products.json")}"
	local OUTPUT="$PWD/out/${PRODUCT}_${SUITE}_${EDITION}"
	mkdir -p "$OUTPUT"
	echo "Building ${PRODUCT} ${SUITE} ${EDITION}..."

	local i
	if i="$(jq -er --arg product "$PRODUCT" '.[] | select(.product == $product).override_kernel' "$SCRIPT_DIR/../../share/rsdk/configs/products.json")"; then
		RSDK_OPTION_KERNEL_OVERRIDE="${RSDK_OPTION_KERNEL_OVERRIDE:-$i}"
	fi
	if i="$(jq -er --arg product "$PRODUCT" '.[] | select(.product == $product).override_firmware' "$SCRIPT_DIR/../../share/rsdk/configs/products.json")"; then
		RSDK_OPTION_FIRMWARE_OVERRIDE="${RSDK_OPTION_FIRMWARE_OVERRIDE:-$i}"
	fi
	if i="$(jq -er --arg product "$PRODUCT" '.[] | select(.product == $product).override_product' "$SCRIPT_DIR/../../share/rsdk/configs/products.json")"; then
		RSDK_OPTION_PRODUCT_OVERRIDE="${RSDK_OPTION_PRODUCT_OVERRIDE:-$i}"
	fi

	if [[ $RSDK_OPTION_CACHE == "false" ]] || ([[ -f "$OUTPUT/$RSDK_OPTION_ROOTFS" ]] && (($(du -b "$OUTPUT/$RSDK_OPTION_ROOTFS" | cut -f 1) == 0))); then
		sudo rm -rf "$OUTPUT/$RSDK_OPTION_ROOTFS"
	fi

	if [[ ! -e "$OUTPUT/$RSDK_OPTION_ROOTFS" ]]; then
		generate_rootfs
	fi

	generate_image
}

main "$@"
